Name Attribute

Group attribute name used to uniquely identify group and its results within results structure. This attribute is a dot separated string, there is every dot represents a next level in hierarchy. This string is split into path items using dot character and converted into nested hierarchy of dictionaries and/or lists.

Consider a group with this name attribute value:

<group name="interfaces.vlan.L3.vrf-enabled">
interface {{ interface }}
  description {{ description }}
  ip address {{ ip }}/{{ mask }}
  vrf {{ vrf }}
</group>

If below data parsed with that template:

interface Vlan777
  description Management
  ip address 192.168.0.1/24
  vrf MGMT

This result will be produced:

[
    {
        "interfaces": {
            "SVIs": {
                "L3": {
                    "vrf-enabled": {
                        "description": "Management",
                        "interface": "Vlan777",
                        "ip": "192.168.0.1",
                        "mask": "24",
                        "vrf": "MGMT"
                    }
                }
            }
        }
    }
]

Name attribute allows to from arbitrary (from practical perspective) depth structure in deterministic fashion, enabling further programmatic consumption of produced results.

Path formatters

By default ttp assumes that all the path items must be joined into a dictionary structure, in other words group name “item1.item2.item3” will be transformed into nested dictionary:

{"item1":
     {"item2":
      {"item3": {}
    }
  }
}

That structure will be populated with results as parsing progresses, but in case if for “item3” more than single result datum needs to be saved, ttp will transform “item3” child to list and save further results by appending them to that list. That process happens automatically but can be influenced using path formatters.

Supported path formatters * and ** for group name attribute can be used following below rules:

  • If single start character * used as a suffix (appended to the end) of path item, next level (child) of this path item always will be a list
  • If double start character ** used as a suffix (appended to the end) of path item, next level (child) of this path item always will be a dictionary

Example

Consider this group with name attribute formed in such a way that interfaces item child will be a list and child of L3 path item also will be a list.:

<group name="interfaces*.vlan.L3*.vrf-enabled">
interface {{ interface }}
  description {{ description }}
  ip address {{ ip }}/{{ mask }}
  vrf {{ vrf }}
</group>

If below data parsed with that template:

interface Vlan777
  description Management
  ip address 192.168.0.1/24
  vrf MGMT

This result will be produced:

[
    {
        "interfaces": [              <----this is the start of nested list
            {
                "vlan": {
                    "L3": [          <----this is the start of another nested list
                        {
                            "vrf-enabled": {
                                "description": "Management",
                                "interface": "Vlan777",
                                "ip": "192.168.0.1",
                                "mask": "24",
                                "vrf": "MGMT"
                            }
                        }
                    ]
                }
            }
        ]
    }
]

Dynamic Path

Above are examples of static path, where all the path items are known and predefined beforehand, however, ttp supports dynamic path formation using match variable results for certain match variable names, i.e we have match variable name set to interface and correspondent match result would be Gi0/1, it is possible to use Gi0/1 as a path item.

Search for dynamic path item value happens using below sequence:

  • First - group match results searched for path item value,
  • Second - upper group results cache (latest values) used,
  • Third - template variables searched for path item value,
  • Last - group results discarded as invalid

Dynamic path items specified in group name attribute using “{{ item_name }}” format, there “{{ item_name }}” dynamically replaced with value found using above sequence.

Example-1

In this example interface variable match values will be used to substitute {{ interface }} dynamic path items.

Data:

interface Port-Chanel11
  description Storage
!
interface Loopback0
  description RID
  ip address 10.0.0.3/24
!
interface Vlan777
  description Management
  ip address 192.168.0.1/24
  vrf MGMT

Template:

<group name="interfaces.{{ interface }}">
interface {{ interface }}
  description {{ description }}
  ip address {{ ip }}/{{ mask }}
  vrf {{ vrf }}
</group>

Result:

[
    {
        "interfaces": {
            "Loopback0": {
                "description": "RID",
                "ip": "10.0.0.3",
                "mask": "24"
            },
            "Port-Chanel11": {
                "description": "Storage"
            },
            "Vlan777": {
                "description": "Management",
                "ip": "192.168.0.1",
                "mask": "24",
                "vrf": "MGMT"
            }
        }
    }
]

Because each path item is a string, and each item produced by spilling name attributes using ‘.’ dot character, it is possible to produce dynamic path there portions of path item will be dynamically substituted.

Data:

interface Port-Chanel11
  description Storage
!
interface Loopback0
  description RID
  ip address 10.0.0.3/24
!
interface Vlan777
  description Management
  ip address 192.168.0.1/24
  vrf MGMT

Template:

<group name="interfaces.cool_{{ interface }}_interface">
interface {{ interface }}
  description {{ description }}
  ip address {{ ip }}/{{ mask }}
  vrf {{ vrf }}
</group>

Result:

[
    {
        "interfaces": {
            "cool_Loopback0_interface": {
                "description": "RID",
                "ip": "10.0.0.3",
                "mask": "24"
            },
            "cool_Port-Chanel11_interface": {
                "description": "Storage"
            },
            "cool_Vlan777_interface": {
                "description": "Management",
                "ip": "192.168.0.1",
                "mask": "24",
                "vrf": "MGMT"
            }
        }
    }
]

Note

Substitution of dynamic path items happens using re.sub method without the limit set on the count of such a substitutions, e.g. if path item “cool_{{ interface }}_interface_{{ interface }}” and if interface value is “Gi0/1” resulted path item will be “cool_Gi0/1_interface_Gi0/1”

Nested hierarchies also supported with dynamic path, as if no variable found in the group match results ttp will try to find variable in the dynamic path cache or template variables.

Example-3

Data:

ucs-core-switch-1#show run | section bgp
router bgp 65100
  vrf CUST-1
    neighbor 59.100.71.193
      remote-as 65101
      description peer-1
      address-family ipv4 unicast
        route-map RPL-1-IMPORT-v4 in
        route-map RPL-1-EXPORT-V4 out
      address-family ipv6 unicast
        route-map RPL-1-IMPORT-V6 in
        route-map RPL-1-EXPORT-V6 out
    neighbor 59.100.71.209
      remote-as 65102
      description peer-2
      address-family ipv4 unicast
        route-map AAPTVRF-LB-BGP-IMPORT-V4 in
        route-map AAPTVRF-LB-BGP-EXPORT-V4 out

Template:

<vars>
hostname = "gethostname"
</vars>

<group name="{{ hostname }}.router.bgp.BGP_AS_{{ asn }}">
router bgp {{ asn }}
  <group name="vrfs.{{ vrf_name }}">
  vrf {{ vrf_name }}
    <group name="peers.{{ peer_ip }}">
    neighbor {{ peer_ip }}
      remote-as {{ peer_asn }}
      description {{ peer_description }}
      <group name="afi.{{ afi }}.unicast">
      address-family {{ afi }} unicast
        route-map {{ rpl_in }} in
        route-map {{ rpl_out }} out
      </group>
    </group>
   </group>
</group>

Result:

- ucs-core-switch-1:
    router:
      bgp:
        BGP_AS_65100:
          vrfs:
            CUST-1:
              peers:
                59.100.71.193:
                  afi:
                    ipv4:
                      unicast:
                        rpl_in: RPL-1-IMPORT-v4
                        rpl_out: RPL-1-EXPORT-V4
                    ipv6:
                      unicast:
                        rpl_in: RPL-1-IMPORT-V6
                        rpl_out: RPL-1-EXPORT-V6
                  peer_asn: '65101'
                  peer_description: peer-1
                59.100.71.209:
                  afi:
                    ipv4:
                      unicast:
                        rpl_in: RPL-2-IMPORT-V6
                        rpl_out: RPL-2-EXPORT-V6
                  peer_asn: '65102'
                  peer_description: peer-2

Dynamic path with path formatters

Dynamic path with path formatters is also supported. In example below child for interfaces will be a list.

Example

Data:

interface Port-Chanel11
  description Storage
!
interface Loopback0
  description RID
  ip address 10.0.0.3/24
!
interface Vlan777
  description Management
  ip address 192.168.0.1/24
  vrf MGMT

Template:

<group name="interfaces*.{{ interface }}">
interface {{ interface }}
  description {{ description }}
  ip address {{ ip }}/{{ mask }}
  vrf {{ vrf }}
</group>

Result:

[
    {
        "interfaces": [
            {
                "Loopback0": {
                    "description": "RID",
                    "ip": "10.0.0.3",
                    "mask": "24"
                },
                "Port-Chanel11": {
                    "description": "Storage"
                },
                "Vlan777": {
                    "description": "Management",
                    "ip": "192.168.0.1",
                    "mask": "24",
                    "vrf": "MGMT"
                }
            }
        ]
    }
]

No name attribute

If no nested functionality required or results structure needs to be kept as flat as possible, templates without <group> tag can be used - so called non hierarchical templates.

There is a notion of top <group> tag exists, that at the tag that located in the top of xml document hierarchy, that tag can be lacking name attribute as well.

In both cases above, ttp will automatically reconstruct <group> tag and name attribute for it, setting name to “_anonymous_” value. At the end _anonymous_ path will be stripped of results tree to flatten it.

Note

<group> tag without name attribute does have support for all the other group attributes as well as nested groups, however, nested groups must have name attribute set on them otherwise nested hierarchy will not be preserved leading to unpredictable results.

Warning

Template variables name attribute ignored if groups with “_anonymous_” path used, as a result template variables will not be save into results.

Example

Example for <group> without name attribute.

Data:

interface Port-Chanel11
  description Storage
!
interface Loopback0
  description RID
  ip address 10.0.0.3/24
!
interface Vlan777
  description Management
  ip address 192.168.0.1/24
  vrf MGMT
!

Template:

<group>
interface {{ interface }}
  description {{ description }}
<group name = "ips">
  ip address {{ ip }}/{{ mask }}
</group>
  vrf {{ vrf }}
!{{_end_}}
</group>

Result:

[
    {
        "description": "Storage",
        "interface": "Port-Chanel11"
    },
    {
        "description": "RID",
        "interface": "Loopback0",
        "ips": {
            "ip": "10.0.0.3",
            "mask": "24"
        }
    },
    {
        "description": "Management",
        "interface": "Vlan777",
        "ips": {
            "ip": "192.168.0.1",
            "mask": "24"
        },
        "vrf": "MGMT"
    }
]

Null path name attribute

It is possible to specify null path as a name, null path looks like name="_" or null path can be used as a first item in the path - name="_.nextlevel".

Special handling implemented for null path - TTP will merge results with parent for group with null path, as a result null path _ will not appear in results.

One of the usecases for this feature is to create a group that will behave like a normal group in terms of results forming and processing, but will merge with parent in the process of saving into overall results.

Example

In this example peer_software used together with _line_ indicator to extract results, however, for _line_ to behave properly it was defined within separate group with explicit _stat_ and _end_ indicators. First this is how template would look like without null path:

<input load="text">
Device ID: switch-2.net
IP address: 10.251.1.49

Version :
Cisco Internetwork Operating System Software
IOS (tm) s72033_rp Software (s72033_rp-PK9SV-M), Version 12.2(17d)SXB11a, RELEASE SOFTWARE (fc1)

advertisement version: 2
</input>

<group>
Device ID: {{ peer_hostname }}
IP address: {{ peer_ip }}

<group name="peer_software">
Version : {{ _start_ }}
{{ peer_software | _line_ }}
{{ _end_ }}
</group>

</group>

And result would be:

[
    [
        {
            "peer_hostname": "switch-2.net",
            "peer_ip": "10.251.1.49",
            "peer_software": {
                "peer_software": "Cisco Internetwork Operating System Software \nIOS (tm) s72033_rp Software (s72033_rp-PK9SV-M), Version 12.2(17d)SXB11a, RELEASE SOFTWARE (fc1)"
            }
        }
    ]
]

Above results has a bit of redundancy in them as they have unnecessary hierarchy to store peer_software details, to avoid that null path can be used:

<input load="text">
Device ID: switch-2.net
IP address: 10.251.1.49

Version :
Cisco Internetwork Operating System Software
IOS (tm) s72033_rp Software (s72033_rp-PK9SV-M), Version 12.2(17d)SXB11a, RELEASE SOFTWARE (fc1)

advertisement version: 2
</input>

<group>
Device ID: {{ peer_hostname }}
IP address: {{ peer_ip }}

<group name="_">
Version : {{ _start_ }}
{{ peer_software | _line_ }}
{{ _end_ }}
</group>

</group>

Results with new template:

[
    [
        {
            "peer_hostname": "switch-2.net",
            "peer_ip": "10.251.1.49",
            "peer_software": "Cisco Internetwork Operating System Software \nIOS (tm) s72033_rp Software (s72033_rp-PK9SV-M), Version 12.2(17d)SXB11a, RELEASE SOFTWARE (fc1)"
        }
    ]
]

Even though peer_software match variable was defined in separate group, because of null path, it was merged with parent group, flattening results structure.